# A part of NonVisual Desktop Access (NVDA)
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
# Copyright (C) 2017-2022 NV Access Limited, Cyrille Bougot

"""appModule for Microsoft Skype for business. """

import ui
from NVDAObjects.UIA import UIA
import appModuleHandler
from logHandler import log

import re


class NetUIRicherLabel(UIA):
	"""A label sometimes found within list items that can fire live region changes, such as for chat messages."""

	def event_liveRegionChange(self):
		# The base liveRegionChange event is not enough as Skype for Business concatinates recent chat messages from the same person within the same minute
		# Therefore, specifically strip out the chat content and only report the most recent part added.
		# When not empty, the object's name contains the full message (I.e. person: content, timestamp)
		# loosely separated by commas.
		# Example string: "Michael Curran : , , Hello\r\n\r\nThis is a test , 10:45 am."
		# Where person is "Michael Curran", content is "Hello\nThis is a test" and timestamp is "10:45 am" 
		
		# Normalize the usage of end-of-line characters (name and value seem to expose them differently, which would break comparison)
		fullText=self.name.replace('\r\n\r\n','\n')
		
		# At the object's creation, an unuseful liveRegionChange event is triggered with an empty name,
		# so we discard it.
		if not self.name.strip():
			return
		
		if self.value is not None:
			# For some versions of Lync / Skype for Business, the object's value contains just the content.
			# Example: "Hello\rThis is a test"
			# We are only interested in person and content
			# Therefore use value (content) to  locate and split off the person from the name (fullText)
			content = self.value.replace('\r', '\n').strip()
			contentStartIndex = fullText.find(content)
			pretext = fullText[:contentStartIndex]
		else:
			# For other versions of Lync / Skype for Business, self.value is just None.
			# So we just look at self.name formatting to split content from person and timestamp (less robust).
			pattern = r'^(?P<name>.+?): (?P<priority>.*?), , (?P<content>.+), (?P<status>.*?), (?P<timestamp>.+?)$'
			match = re.match(pattern, self.name, flags=re.DOTALL)
			if match:
				pretext = match['name']
				priority = match['priority']
				content = match['content']
				status = match['status']
				if priority:
					content = priority + ', ' + content
				if status:
					content = content + ', ' + status
			else:
				# Some messages may not follow the person+priority+content+status+timestamp pattern.
				# E.g. call start, call end or first message which is a privacy warning.
				# The match may also fail if an unexpected conversation pattern exists in some versions or uses of Skype.
				# In all these cases, return the whole message.
				# Also log the message in case unexpected conversation pattern has to be debugged.
				log.debug(f'No message pattern found in the following message: {self.name}')
				pretext = ''
				content = self.name
			content = content.replace('\r', '\n').strip()
		contentLines=content.split('\n')
		# There are some annoying comma characters  after the person's name 
		pretext=pretext.replace(' ,','')
		# If the objects are the same, the person is the same, and the new content is the old content but with more appended, report the appended content
		# Otherwise, report the person and the initial content
		runtimeID=self.UIAElement.getRuntimeId()
		lastRuntimeID,lastPretext,lastContentLines=self.appModule._lastLiveChatMessageData
		contentLinesLen=len(contentLines)
		lastContentLinesLen=len(lastContentLines)
		if runtimeID==lastRuntimeID and pretext==lastPretext and contentLinesLen>lastContentLinesLen and contentLines[:lastContentLinesLen]==lastContentLines:
			message="\n".join(contentLines[lastContentLinesLen:])
		else:
			message=pretext+content
		ui.message(message)
		# Cache the message data for later possible comparisons 
		self.appModule._lastLiveChatMessageData=runtimeID,pretext,contentLines

class AppModule(appModuleHandler.AppModule):

	# data to store the last chat message (runtime ID,person,content lines)
	_lastLiveChatMessageData=[],"",[]

	def chooseNVDAObjectOverlayClasses(self,obj,clsList):
		if isinstance(obj,UIA) and obj.UIAElement.cachedClassName=='NetUIRicherLabel':
			clsList.insert(0,NetUIRicherLabel)
		return clsList

